import json
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from lxml import etree
import csv
from selenium.webdriver.edge.options import Options
from selenium.webdriver.common.action_chains import ActionChains

url = 'https://movie.douban.com/explore?'

# 获取当前Edge版本（需手动更新）
EDGE_VERSION = "135.0.3179.73"
# todo 创建驱动参数
option = Options()
option.add_experimental_option("detach", True)  # todo 阻止自动关闭
option.add_argument("--disable-blink-features=AutomationControlled")  # todo 防止网站检测到自动化测试工具的控制

# todo Edge专属伪装
option.add_argument(
    f"user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{EDGE_VERSION.split('.')[0]}.0.0.0 Safari/537.36 Edg/{EDGE_VERSION}")
option.add_argument("accept-language=zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7")
option.add_argument("referer=https://www.douban.com/")
option.add_argument("sec-ch-ua-platform=\"Windows\"")
option.add_argument("sec-ch-ua-mobile=?0")
option.add_argument("--enable-features=msEdgeExperimentalFeatures")

# todo 创建浏览器驱动
driver = webdriver.Edge(options=option)

# todo 禁用自动化控制标志
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": """
    Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
    Object.defineProperty(navigator, 'hardwareConcurrency', {value: 8});
    """
})

# todo 创建一个用于缓慢滑动的
actions = ActionChains(driver)

# todo 打开网页
driver.get(url)
time.sleep(3)
# 网页最大化
driver.maximize_window()
time.sleep(1)

#   todo 先给文件写入字段名
# with open('source.csv', 'a', newline='', encoding='utf-8') as file:
#     # 创建csv写入对象
#     writer = csv.writer(file)
#     writer.writerow([
#         "name", "year", "guojia", "class", "director", "zhujue", "mark", "image_url", "info_url"
#     ])

#   todo 点击全部
try:
    next_icon = WebDriverWait(driver, 10).until(
        # todo 外面的button不让点击，所以我们等待里面li标签加载完，点击里面的标签
        EC.element_to_be_clickable((By.XPATH, '//*[@id="app"]/div/ul/li[1]'))
    )
    next_icon.click()
    time.sleep(5)
except Exception as e:
    print(f"通过图标点击失败: {e}")


#   todo 模拟点击不同类型的电影
for u in range(2,22):
    #   todo 拿到网页的html源码，点击不同类型的电影
    # todo 拿到当前网页的字符串html源码
    str_html = driver.page_source
    # todo 将字符串转化为html对象，为了下面的xpath爬取数据
    html = etree.HTML(str_html)


    #   todo 展开电影类型
    driver.find_element(By.XPATH, '//*[@id="app"]/div/ul/li[1]').click()

    # todo 拿到当前网页的字符串html源码
    str_html = driver.page_source
    # todo 将字符串转化为html对象，为了下面的xpath爬取数据
    html = etree.HTML(str_html)

    #   todo 使用html.xpath点击不了div和li元素，但是可以使用driver.find_element点击div这些的
    driver.find_element(By.XPATH,'//*[@id="app"]/div/div/div[1]/div/div[1]/div[1]/div/div').click()

    #   todo 点击各种类型的电影
    movie_type = driver.find_element(By.XPATH, '//*[@id="app"]/div/div/div[1]/div/div[1]/div[1]/div/div[2]/div/div/ul/li['+str(u)+']/span')
    driver.execute_script("arguments[0].click();", movie_type)


    # todo 由于数据是动态加载，为了避免重复获取已经爬取过的数据，下面定义一个变量接收已经获取的了ul的长度
    before = 0
    # todo 存储数据的数组
    rows = []
    for k in range(1, 5):  # 每种类型爬取10段数据
        print("获取第", k, "页的数据")
        # todo 缓慢滚动到页面底部 加载数据     可以根据下面循环滑动的次数，来决定下滑的距离
        for _ in range(5):  # 分16步滚动
            actions.scroll_by_amount(0, 500).perform()  # 每次滚动500像素
            time.sleep(0.3)  # 控制滚动速度
        time.sleep(1)

        # todo 由于是动态加载数据，点击了加载更多数据之后，网页结构发生变化，所以下面需要重新获取网页的html源码
        # todo 拿到当前网页的字符串html源码
        str_html = driver.page_source
        # todo 将字符串转化为html对象，为了下面的xpath爬取数据
        html = etree.HTML(str_html)

        # todo 数据是ul里面嵌套li标签的，所以我们先拿到最外层的ul标签
        ul = html.xpath('//*[@id="app"]/div/div/div[2]/ul/li')

        # todo 只处理新增的数据
        current = len(ul)
        if current > before:
            new_ul = ul[before:]  # 用切片拿到最新的数据
            # todo 进入循环遍历里面的li标签
            for x in new_ul:
                row = []
                # todo 拿到里面的电影名字
                name = x.xpath('./a/div/div[2]/div/div[1]/span/text()')
                print(name)
                row.append(name[0])

                # todo 拿到电影的上映年份，以及上映国家，电影的类型，电影的导演，电影的主角
                info_list = x.xpath('./a/div/div[2]/div/div[1]/div/text()')
                print(info_list[0].split(" / "))
                try:
                    row.append(info_list[0].split(" / ")[0])  # 年份
                    row.append(info_list[0].split(" / ")[1])  # 国家
                    row.append(info_list[0].split(" / ")[2])  # 类型
                    row.append(info_list[0].split(" / ")[3])  # 导演
                    row.append(info_list[0].split(" / ")[4])  # 主角
                except Exception as e:
                    print("报错了:", e)

                # todo 拿到电影的豆瓣评分
                mark = x.xpath('./a/div/div[2]/div/div[2]/span[2]/text()')
                print(mark)
                row.append(mark[0])

                # todo 拿到电影照片的连接
                image_url = x.xpath('./a/div/div[1]/div/img/@src')
                print(image_url)
                row.append(image_url[0])

                # todo 拿到电影的详细页面的url
                info_url = x.xpath('./a/@href')
                print(info_url)
                row.append(info_url[0])

                rows.append(row)
            # todo 爬取完了之后把当前的ul的长度赋值给before
            # before = current
            #
            # for t in rows:
            #     print(t)
            # # todo 将这一页的数据写入文件
            # with open('source.csv', 'a', newline='', encoding='utf-8') as file:
            #     # 创建csv写入对象
            #     writer = csv.writer(file)
            #     # 写入数据
            #     writer.writerows(rows)

        # todo 点击加载更多数据
        try:
            next_icon = WebDriverWait(driver, 10).until(
                # todo 外面的button不让点击，所以我们等待里面li标签加载完，点击里面的标签
                EC.element_to_be_clickable((By.XPATH, '//*[@id="app"]/div/div/div[2]/div/button'))
            )
            next_icon.click()
            time.sleep(5)
        except Exception as e:
            print(f"通过图标点击失败: {e}")